package cn.etynit.service.impl;

import cn.etynit.domain.*;
import cn.etynit.dto.AccountLoginDto;
import cn.etynit.dto.PayDto;
import cn.etynit.dto.RechargeDto;
import cn.etynit.dto.VisitorDto;
import cn.etynit.exception.GlobalException;
import cn.etynit.exception.GlobalExceptionCodeEnum;
import cn.etynit.mapper.UserMapper;
import cn.etynit.mms.feign.*;
import cn.etynit.result.JsonResult;
import cn.etynit.service.*;
import cn.etynit.util.AssertUtil;
import cn.etynit.vo.Logininfo;
import cn.etynit.vo.RechargeVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author etyn
 * @since 2022-12-08
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private ExpenseElectricityService expenseElectricityService;

    @Autowired
    private ExpenseNaturalGasService expenseNaturalGasService;

    @Autowired
    private ExpenseTapWaterService expenseTapWaterService;

    @Autowired
    private ExpensesPropertyService expensesPropertyService;

    @Autowired
    private ExpenseRechargeService expenseRechargeService;

    @Autowired
    private ExpenseService expenseService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private IUserFamilyService userFamilyService;

    @Autowired
    private VisitorLogService visitorLogService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private InformService informService;

    private static final String ADDITION_PROPRIETOR_SUCCEED = "添加业主成功！";

    private static final String DOOR_OPENING_PROMPT = "门开啦！";

    /**
     * 添加业主
     * @param user
     * @return
     */
    @Override
    public JsonResult addingAnOwner(User user) {
        // 参数校验
        String account = user.getAccount();
        AssertUtil.isAccount(account,GlobalExceptionCodeEnum.USER_ACCOUNT_INCORRECT_FORMAT);
        String password = user.getPassword();
        AssertUtil.isPassword(password, GlobalExceptionCodeEnum.USER_PASSWORD_INCORRECT_FORMAT);
        String phone = user.getPhone();
        AssertUtil.isPhone(phone,GlobalExceptionCodeEnum.USER_PHONE_INCORRECT_FORMAT);
        insert(user);
        Long userId = user.getId();
        BigDecimal money = new BigDecimal(0);
        // 初始化电费表
        initializeAmmeter(userId, money);
        // 初始化燃气表
        initializeGasometer(userId, money);
        // 初始化水表
        initializeWaterMeter(userId, money);
        // 初始化物业费用表
        initializePropertyFeeMeter(userId, money);
        return JsonResult.success(ADDITION_PROPRIETOR_SUCCEED);
    }

    /**
     * 缴费
     * @param payDto
     * @return
     */
    @Override
    public JsonResult Pay(PayDto payDto,String token) {
        // redis获取登录信息
        Logininfo logininfo = (Logininfo)redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 为null登录过期
        AssertUtil.isTrue(logininfo.getType() == 2,GlobalExceptionCodeEnum.ERROR); // 类型不为2代表不是业主
        Long userId = logininfo.getId(); // 业主id
        Integer type = payDto.getType(); // 缴费类型
        Integer month = payDto.getMonth(); // 月份
        BigDecimal bigDecimal = new BigDecimal(0);
        Date date = new Date();
        if (type == 1){ // 交电费
            JsonResult jsonResult = expenseElectricityService.selectByUserId(userId);
            AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR); // 水费单不存在报错
            ExpenseElectricity expenseElectricity = JSON.parseObject(JSONObject.toJSONString(jsonResult.getData()), ExpenseElectricity.class);
            AssertUtil.isNotNull(expenseElectricity,GlobalExceptionCodeEnum.ERROR);
            BigDecimal o = expenseElectricity.getResidue();
            BigDecimal a = expenseElectricity.getAccumulative();
            if (o.compareTo(a) < 0){ // 余额不足报错
                throw new GlobalException(GlobalExceptionCodeEnum.ERROR);
            }
            expenseElectricity.setResidue(expenseElectricity.getResidue().subtract(expenseElectricity.getAccumulative()));
            expenseElectricity.setAccumulative(bigDecimal);
            // 更新缴费单
            updateDemandNote(userId, type, date, month);
            return expenseElectricityService.saveOrUpdate(expenseElectricity);
        } else if (type == 2){ // 交水费
            JsonResult jsonResult = expenseTapWaterService.selectByUserId(userId);
            AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR);
            ExpenseTapWater expenseTapWater = JSON.parseObject(JSONObject.toJSONString(jsonResult.getData()), ExpenseTapWater.class);
            AssertUtil.isNotNull(expenseTapWater,GlobalExceptionCodeEnum.ERROR);
            if (expenseTapWater.getResidue().compareTo(expenseTapWater.getAccumulative()) < 0){ // 余额不足报错
                throw new GlobalException(GlobalExceptionCodeEnum.ERROR);
            }
            expenseTapWater.setResidue(expenseTapWater.getResidue().subtract(expenseTapWater.getAccumulative()));
            expenseTapWater.setAccumulative(bigDecimal);
            // 更新缴费单
            updateDemandNote(userId, type, date, month);
            return expenseTapWaterService.saveOrUpdate(expenseTapWater);
        } else if (type == 3){ // 交燃气费
            JsonResult jsonResult = expenseNaturalGasService.selectByUserId(userId);
            AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCodeEnum.ERROR);
            ExpenseNaturalGas expenseNaturalGas = JSON.parseObject(JSONObject.toJSONString(jsonResult.getData()), ExpenseNaturalGas.class);
            AssertUtil.isNotNull(expenseNaturalGas,GlobalExceptionCodeEnum.ERROR);
            if (expenseNaturalGas.getResidue().compareTo(expenseNaturalGas.getAccumulative()) < 0){ // 余额不足报错
                throw new GlobalException(GlobalExceptionCodeEnum.ERROR);
            }
            expenseNaturalGas.setResidue(expenseNaturalGas.getResidue().subtract(expenseNaturalGas.getAccumulative()));
            expenseNaturalGas.setAccumulative(bigDecimal);
            // 更新缴费单
            updateDemandNote(userId, type, date, month);
            return expenseNaturalGasService.saveOrUpdate(expenseNaturalGas);
        } else {
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR);
        }
    }

    /**
     * 根据业主id获取有效活动
     * @param token
     * @return
     */
    @Override
    public List<Activity> getEventNotification(String token) {
        // redis获取登录信息
        Logininfo logininfo = (Logininfo)redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 为null登录过期
        AssertUtil.isTrue(logininfo.getType() == 2,GlobalExceptionCodeEnum.ERROR); // 类型不为2代表不是业主
        Long userId = logininfo.getId(); // 业主id
//        // 根据id判断当前用户是否存在
//        User user = selectById(userId);
//        AssertUtil.isNotNull(user,GlobalExceptionCodeEnum.ERROR);
        // 查询所有活动
        Date date = new Date();
        List<Activity> activitieList = new ArrayList<>();
        JsonResult list = activityService.list();
        AssertUtil.isTrue(list.isSuccess(),GlobalExceptionCodeEnum.ERROR);
        List<Activity> activities = JSON.parseArray(JSONObject.toJSONString(list.getData()), Activity.class);
        activities.forEach(m ->{
            Date expirationTime = m.getExpirationTime();
            // 如果活动过期时间没有或者还未过期，则可以查看
            if (expirationTime == null || expirationTime.after(date)){
                activitieList.add(m);
            }
        });
        return activitieList;
    }

    /**
     * 访客
     * @param visitorDto
     * @return
     */
    @Override
    public JsonResult visitor(VisitorDto visitorDto) {
        // 参数校验
        String name = visitorDto.getName();
        AssertUtil.isNotNull(name,GlobalExceptionCodeEnum.ERROR);
        String phone = visitorDto.getPhone();
        AssertUtil.isNotNull(phone,GlobalExceptionCodeEnum.ERROR);
        String visitorName = visitorDto.getVisitorName();
        AssertUtil.isNotNull(visitorName,GlobalExceptionCodeEnum.ERROR);
        String visitorPhone = visitorDto.getVisitorPhone();
        AssertUtil.isPhone(visitorPhone,GlobalExceptionCodeEnum.ERROR);
        AssertUtil.isNotNull(visitorPhone,GlobalExceptionCodeEnum.ERROR);
        // 创建访客日志对象
        JsonResult visitor = visitorLogService.getVisitor(visitorName, visitorPhone);
        AssertUtil.isTrue(visitor.isSuccess(),GlobalExceptionCodeEnum.ERROR);
        VisitorLog visitorLog = JSON.parseObject(JSONObject.toJSONString(visitor.getData()), VisitorLog.class);
        Date date = new Date();
        if (visitorLog.getId() == null){
            visitorLog.setName(visitorName);
            visitorLog.setPhone(visitorPhone);
            visitorLog.setEntranceTime(date);
            // 通过姓名和电话查询业主或家庭成员是否存在
            Wrapper<User> wrapper = new EntityWrapper<>();
            wrapper.eq("name",name);
            wrapper.eq("phone",phone);
            User user = selectOne(wrapper);
            if (user != null){
                visitorLog.setUserOrFamilyId(user.getId());
                visitorLog.setUserOrFamilyName(user.getName());
                visitorLogService.saveOrUpdate(visitorLog);
                return JsonResult.success(DOOR_OPENING_PROMPT);
            } else {
                UserFamily userFamily = userFamilyService.visitor(name,phone);
                AssertUtil.isNotNull(userFamily,GlobalExceptionCodeEnum.ERROR);
                visitorLog.setUserOrFamilyId(userFamily.getId());
                visitorLog.setUserOrFamilyName(userFamily.getFamilyName());
                visitorLogService.saveOrUpdate(visitorLog);
                return JsonResult.success(DOOR_OPENING_PROMPT);
            }
        } else {
            visitorLog.setEntranceTime(date);
            visitorLogService.saveOrUpdate(visitorLog);
            return JsonResult.success(DOOR_OPENING_PROMPT);
        }
    }

    /**
     * 访客离开
     * @param name
     * @param phone
     * @return
     */
    @Override
    public JsonResult visitorsLeave(String name, String phone) {
        JsonResult visitor = visitorLogService.getVisitor(name, phone);
        AssertUtil.isTrue(visitor.isSuccess(),GlobalExceptionCodeEnum.ERROR);
        VisitorLog visitorLog = JSON.parseObject(JSONObject.toJSONString(visitor.getData()), VisitorLog.class);
        visitorLog.setLeaveTime(new Date());
        JsonResult jsonResult = visitorLogService.saveOrUpdate(visitorLog);
        jsonResult.setMessage(DOOR_OPENING_PROMPT);
        return jsonResult;
    }

    /**
     * 业主登录
     * @param accountLoginDto
     * @return
     */
    @Override
    public User accountLogin(AccountLoginDto accountLoginDto) {
        String account = accountLoginDto.getAccount();
        String password = accountLoginDto.getPassword();
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("account",account);
//        wrapper.eq("password",password);
        User user = selectOne(wrapper);
        if (user == null){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 账号错误
        }
        if (!user.getPassword().equals(password)){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 密码错误
        }
        return user;
    }

    /**
     * 查询有效通知
     * @param token
     * @return
     */
    @Override
    public List<Inform> viewNotifications(String token) {
        // redis获取登录信息
        Logininfo logininfo = (Logininfo)redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 为null登录过期
        AssertUtil.isTrue(logininfo.getType() == 2,GlobalExceptionCodeEnum.ERROR); // 类型不为2代表不是业主
        List<Inform> listInform = new ArrayList<>();
        JsonResult list = informService.list();
        Date date = new Date();
        List<Inform> informs = JSON.parseArray(JSONObject.toJSONString(list.getData()), Inform.class);
        // 遍历所有通知
        informs.forEach(m ->{
            // 返回通知过期时间为空或者未过期的
            Date expirationTime = m.getExpirationTime();
            if (expirationTime == null || expirationTime.after(date)){
                listInform.add(m);
            }
        });
        return listInform;
    }


    /**
     * 费用充值
     * @param rechargeDto
     * @return
     */
    @Override
    public JsonResult ChargeTopUp(RechargeDto rechargeDto,String token) {
        // redis获取登录信息
        Logininfo logininfo = (Logininfo)redisTemplate.opsForValue().get(token);
        AssertUtil.isNotNull(logininfo,GlobalExceptionCodeEnum.ERROR); // 为null登录过期
        AssertUtil.isTrue(logininfo.getType() == 2,GlobalExceptionCodeEnum.ERROR); // 类型不为2代表不是业主
        Long userId = logininfo.getId(); // 业主id
        Integer type = rechargeDto.getType(); // 费用充值类型
        BigDecimal money = rechargeDto.getMoney();
        int i = money.compareTo(BigDecimal.ZERO);
        if (i == 0 || i < 0){
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 费用充值不能为0或者负数
        }
        ExpenseRecharge expenseRecharge = new ExpenseRecharge();
        expenseRecharge.setUserId(userId);
        expenseRecharge.setRechargeTime(new Date());
        expenseRecharge.setExpenseType(type);
        expenseRecharge.setMoney(money);
        // 缴费参数
        RechargeVo rechargeVo = new RechargeVo();
        rechargeVo.setMoney(money);
        rechargeVo.setType(type);
        rechargeVo.setUserId(userId);
        if (type == 1){
            JsonResult recharge = expenseElectricityService.recharge(rechargeVo);
            expenseRechargeService.saveOrUpdate(expenseRecharge);
            return recharge;
        } else if (type == 2){
            JsonResult recharge = expenseTapWaterService.recharge(rechargeVo);
            expenseRechargeService.saveOrUpdate(expenseRecharge);
            return recharge;
        } else if (type == 3){
            JsonResult recharge = expenseNaturalGasService.recharge(rechargeVo);
            expenseRechargeService.saveOrUpdate(expenseRecharge);
            return recharge;
        } else {
            throw new GlobalException(GlobalExceptionCodeEnum.ERROR); // 充值费用类型不对
        }
    }

    /**
     * 初始化物业费表
     * @param userId
     * @param money
     */
    private void initializePropertyFeeMeter(Long userId, BigDecimal money) {
        ExpensesProperty expensesProperty = new ExpensesProperty();
        expensesProperty.setExpense(money);
        expensesProperty.setUserId(userId);
        expensesPropertyService.saveOrUpdate(expensesProperty);
    }

    /**
     * 初始化水表
     * @param userId
     * @param money
     */
    private void initializeWaterMeter(Long userId, BigDecimal money) {
        ExpenseTapWater expenseTapWater = new ExpenseTapWater();
        expenseTapWater.setUnitPrice(new BigDecimal(0.2));
        expenseTapWater.setDosage(0);
        expenseTapWater.setReverse(money);
        expenseTapWater.setAccumulative(money);
        expenseTapWater.setResidue(money);
        expenseTapWater.setUserId(userId);
        expenseTapWaterService.saveOrUpdate(expenseTapWater);
    }

    /**
     * 初始化气表
     * @param userId
     * @param money
     */
    private void initializeGasometer(Long userId, BigDecimal money) {
        ExpenseNaturalGas expenseNaturalGas = new ExpenseNaturalGas();
        expenseNaturalGas.setUnitPrice(new BigDecimal(0.51));
        expenseNaturalGas.setDosage(0);
        expenseNaturalGas.setReverse(money);
        expenseNaturalGas.setAccumulative(money);
        expenseNaturalGas.setResidue(money);
        expenseNaturalGas.setUserId(userId);
        expenseNaturalGasService.saveOrUpdate(expenseNaturalGas);
    }

    /**
     * 初始化电表
     * @param userId
     * @param money
     */
    private void initializeAmmeter(Long userId, BigDecimal money) {
        ExpenseElectricity expenseElectricity = new ExpenseElectricity();
        expenseElectricity.setUnitPrice(new BigDecimal(0.52));
        expenseElectricity.setDosage(0);
        expenseElectricity.setFloodSeason(ExpenseElectricity.NOT_IS_FLOOD_SEASON);
        expenseElectricity.setReverse(money);
        expenseElectricity.setAccumulative(money);
        expenseElectricity.setResidue(money);
        expenseElectricity.setUserId(userId);
        expenseElectricityService.saveOrUpdate(expenseElectricity);
    }

    /**
     * 更新缴费单
     * @param userId
     * @param type
     * @param date
     */
    private void updateDemandNote(Long userId, Integer type, Date date, Integer month) {
        JsonResult result = expenseService.inquireCost(type, userId, month);
        AssertUtil.isTrue(result.isSuccess(),GlobalExceptionCodeEnum.ERROR);
        Object obj = result.getData();
        AssertUtil.isNotNull(obj,GlobalExceptionCodeEnum.ERROR);
        Expense expense = JSON.parseObject(JSONObject.toJSONString(obj), Expense.class);
        AssertUtil.isNotNull(expense,GlobalExceptionCodeEnum.ERROR);
        expense.setPayTime(date);
        expense.setPay(Expense.HAVE_PAID);
        expenseService.saveOrUpdate(expense);
    }
}
